package Segmentacao;

import Controle.ManipularImagem;
import Estruturas.Pixel;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.media.jai.PlanarImage;

// ESTA CLASSE AINDA NÃO ESTÁ FINALIZADA!!!!
public class PontosMinimo {

    private Vector<Point> pontos;
    Pixel[][] matrizPixels;
    int height;
    int width;

    public PontosMinimo() {
        pontos = new Vector<Point>();
    }

    public PlanarImage calcularPontosMinimo(PlanarImage source) {

        height = source.getHeight();
        width = source.getWidth();


        /* Converte o vetor de pixels em matriz */
        matrizPixels = ManipularImagem.planarToMatrizPixels(source);

        int max = this.getMaximaIntensidadeDaImagem(source);

        /* Pulei os ultimos pixels nos extremos da imagem
        porque eles são brancos e estavam interferindo na analise.
        Este laço exclui da analise posterior todos os pixels
        considerados abaixo do limiar estabelecido. */
        for (int i = 1; i < height - 1; i++) {
            for (int j = 1; j < width - 1; j++) {
                // Se o pixel é brilhante...
                if (!(matrizPixels[i][j].getNivelCinza() > getLimiar(max, 90))) {
                    matrizPixels[i][j].setNivelCinza(255);
                }
                else
                    matrizPixels[i][j].setNivelCinza(0);
            }
        }

        classificaPixelsClaros();

        return ManipularImagem.matrizPixelsToPlanar(matrizPixels, height, width, source);
    }

    private void classificaPixelsClaros() {

        for (int i = 1; i < height - 1; i++) {
            for (int j = 1; j < width - 1; j++) {
                // Se o pixel é brilhante...
                if (matrizPixels[i][j].getNivelCinza() == 0) {
                    continue;
                } else {
                    Pixel atual = matrizPixels[i][j];
                    ArrayList<Pixel> vizinhos = geraListaVizinhos(atual);

                    // Se o pixel atual tem pelo menos um vizinho mais 'brilhante' que ele
                    // Marca o pixel atual para ser apagado;
                    if (temVizinhoMB(atual)) {
                        atual.setNivelCinza(-1);

                        if (atual.getPMB() == null) {

                            Pixel PMBtemp = buscaPBMVizinhos(vizinhos);
                            if (PMBtemp != null) {
                                atual.setPMB(PMBtemp);
                                atualizaPMBVizinhos(PMBtemp, vizinhos);
                            } else {
                                continue;
                            }
                        } else {
                            atualizaPMBVizinhos(atual.getPMB(), vizinhos);
                        }
                    } else {
                        if (atual.getPMB() == null) {
                            Pixel PMBtemp = buscaPBMVizinhos(vizinhos);
                            if (PMBtemp == null) {
                                atual.setPMB(atual);
                                atualizaPMBVizinhos(atual, vizinhos);
                                continue;
                            } else {
                                atual.setPMB(PMBtemp);
                            }
                        }
                        if (atual.getNivelCinza() > atual.getPMB().getNivelCinza()) {
                            apagaAntigoPMB(atual.getPMB());
                            atual.setPMB(atual);
                            atualizaPMBVizinhos(atual, vizinhos);
                        } else {
                            atual.setNivelCinza(-1);
                            atualizaPMBVizinhos(atual.getPMB(), vizinhos);
                        }
                    }
                } // Fim do else 'pixel atual não é preto'
            }
        }

        for (int i = 1; i < height - 1; i++) {
            for (int j = 1; j < width - 1; j++) {
                if (matrizPixels[i][j].getNivelCinza() == -1) {
                    matrizPixels[i][j].setNivelCinza(130);
                } else {
                    continue;
                }
            }
        }
    }

    // Este método retorna TRUE se o pixel p tem pelo menos um vizinho 'mais brilhante'
    // e FALSE, caso contrário;
    private boolean temVizinhoMB(Pixel p) {

        ArrayList<Pixel> vizinhos = geraListaVizinhos(p);

        for (Pixel vizinho : vizinhos) {
            if (vizinho.getNivelCinza() > p.getNivelCinza()) {
                return true;
            }
        }
        return false;
    }

    private Pixel buscaPBMVizinhos(ArrayList<Pixel> vizinhos) {

        for (Pixel vizinho : vizinhos) {
            if (vizinho.getPMB() != null) {
                return vizinho.getPMB();
            }
        }
        return null;
    }

    private void apagaAntigoPMB(Pixel antigoPMB) {

        int i = antigoPMB.getCoordenadas().y;
        int j = antigoPMB.getCoordenadas().x;

        matrizPixels[i][j].setNivelCinza(-1);
    }

    private void atualizaPMBVizinhos(Pixel PMB, ArrayList<Pixel> vizinhos) {

        for (Pixel vizinho : vizinhos) {
            vizinho.setPMB(PMB);
        }
    }

    // Este método gera a lista de vizinhos claros do pixel p;
    private ArrayList<Pixel> geraListaVizinhos(Pixel p) {

        ArrayList<Pixel> vizinhos = new ArrayList<Pixel>();
        int j = p.getCoordenadas().x;
        int i = p.getCoordenadas().y;

        try {

            if (j > 0 && i > 0 && matrizPixels[i - 1][j - 1].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i - 1][j - 1]);
            }

            if (i > 0 && matrizPixels[i - 1][j].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i - 1][j]);
            }

            if (i > 0 && j < width - 1 && matrizPixels[i - 1][j + 1].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i - 1][j + 1]);
            }

            if (j > 0 && matrizPixels[i][j - 1].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i][j - 1]);
            }

            if (j < width - 1 && matrizPixels[i][j + 1].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i][j + 1]);
            }

            if (i < height - 1 && j > 0 && matrizPixels[i + 1][j - 1].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i + 1][j - 1]);
            }

            if (i < height - 1 && matrizPixels[i + 1][j].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i + 1][j]);
            }

            if (i < height - 1 && j < width - 1 && matrizPixels[i + 1][j + 1].getNivelCinza() > 0) {
                vizinhos.add(matrizPixels[i + 1][j + 1]);
            }

        } catch (Exception e) {
            System.out.println("creca na lista de vizinhos!!");
        }

        return vizinhos;
    }

    /*
     * Este método retorna um valor que determina qual será o limiar
     * que define um pixel como brilhante;
     * @param max  - máximo tom de cinza da imagem;
     * @param porcentagem representa o valor limite do quanto um pixel
     * poderá ser considerado como 'brilhante';
     */
    private static double getLimiar(int max, int porcentagem) {
        return max * porcentagem / 100;
    }

    /* Este método retorna o máximo nivel de cinza presente na imagem */
    private int getMaximaIntensidadeDaImagem(PlanarImage source) {

        int max = 0;
        int[] histograma = ManipularImagem.gerarHistograma(source);

        for (int i = histograma.length - 1; i >= 0; i--) {
            max = histograma[i];
            if (max > 0) {
                return i;
            }
        }
        return max;
    }
}
